package com.zsj.juc.Atomic;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.LongAccumulator;
import java.util.concurrent.atomic.LongAdder;

/**
 * @author zsj
 * @version 1.0
 * @date 2024/5/17 15:43
 * @description 点赞计数器案例
 * <p>
 * 50个线程 每个线程100w次
 */
class ClickNumber {
    int number = 0;

    //使用synchronized
    public synchronized void pp() {
        number++;
    }


    AtomicLong atomicLong = new AtomicLong(0);

    //使用AtomicLong
    public void pp_atomicLong() {
        atomicLong.getAndIncrement();
    }


    LongAdder longAdder = new LongAdder();

    //使用LongAdder
    public void pp_longAdder() {
        longAdder.increment();
    }

    LongAccumulator longAccumulator = new LongAccumulator(Long::sum, 0);

    //使用Accumulator
    public void pp_accumulator() {
        longAccumulator.accumulate(1);
    }


}

public class AccumulatorCompareDemo {

    public static final int _1W = 10000;

    public static final int THREAD_NUMBER = 50;

    public static void main(String[] args) throws InterruptedException {
        ClickNumber clickNumber = new ClickNumber();
        long start;
        long end;
        CountDownLatch countDownLatch1 = new CountDownLatch(THREAD_NUMBER);
        CountDownLatch countDownLatch2 = new CountDownLatch(THREAD_NUMBER);
        CountDownLatch countDownLatch3 = new CountDownLatch(THREAD_NUMBER);
        CountDownLatch countDownLatch4 = new CountDownLatch(THREAD_NUMBER);

        //测试synchronized 方法
        start = System.currentTimeMillis();
        for (int i = 0; i < THREAD_NUMBER; i++) {
            new Thread(() -> {
                try {
                    for (int j = 0; j < 100 * _1W; j++) {
                        //100w次点赞
                        clickNumber.pp();
                    }
                } finally {
                    countDownLatch1.countDown();
                }

            }, i + "t1").start();
        }
        countDownLatch1.await();
        end = System.currentTimeMillis();
        System.out.println("synchronized消耗时间" + (end - start) + "毫秒");


        //测试atomiclong
        start = System.currentTimeMillis();
        for (int i = 0; i < THREAD_NUMBER; i++) {
            new Thread(() -> {
                try {
                    for (int j = 0; j < 100 * _1W; j++) {
                        //100w次点赞
                        clickNumber.pp_atomicLong();
                    }
                } finally {
                    countDownLatch2.countDown();
                }

            }, i + "t2").start();
        }
        countDownLatch2.await();
        end = System.currentTimeMillis();
        System.out.println("atomiclong消耗时间" + (end - start) + "毫秒");

        //测试accumulator
        start = System.currentTimeMillis();
        for (int i = 0; i < THREAD_NUMBER; i++) {
            new Thread(() -> {
                try {
                    for (int j = 0; j < 100 * _1W; j++) {
                        //100w次点赞
                        clickNumber.pp_accumulator();
                    }
                } finally {
                    countDownLatch3.countDown();
                }

            }, i + "t3").start();
        }
        countDownLatch3.await();
        end = System.currentTimeMillis();
        System.out.println("accumulator消耗时间" + (end - start) + "毫秒");

        start = System.currentTimeMillis();
        //测试longAdder
        for (int i = 0; i < THREAD_NUMBER; i++) {
            new Thread(() -> {
                try {
                    for (int j = 0; j < 100 * _1W; j++) {
                        //100w次点赞
                        clickNumber.pp_longAdder();
                    }
                } finally {
                    countDownLatch4.countDown();
                }

            }, i + "t4").start();
        }
        countDownLatch4.await();
        end = System.currentTimeMillis();
        System.out.println("longAdder消耗时间" + (end - start) + "毫秒");

        System.out.println(clickNumber.number);//sync
        System.out.println(clickNumber.atomicLong.get());//atomiclong
        System.out.println(clickNumber.longAccumulator.get());///longaccumulator
        System.out.println(clickNumber.longAdder.sum());//longadder

    }
}
